#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <string>

class Socket
{
public:
   Socket()
      :_sockFd(-1), _backlog(10)
   {}
   // 创建套接字
   bool Sock()
   {
      _sockFd = socket(AF_INET, SOCK_STREAM, 0);
      if (_sockFd < 0) {
         std::cerr << "Socket::Sock()::socket err..." << std::endl;
         return false;
      }
      int opt = 1;
      if (setsockopt(_sockFd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) < 0) {
         std::cerr << "Socket::Sock()::setsockopt err..." << std::endl;
         return false;
      }
      return true;
   }
   // 绑定
   bool Bind(uint16_t port)
   {
      struct sockaddr_in local;
      bzero(&local, sizeof(local));
      local.sin_family = AF_INET;
      local.sin_addr.s_addr = INADDR_ANY;
      local.sin_port = htons(port);
      if (bind(_sockFd, (struct sockaddr*)&local, sizeof(local)) < 0) {
	      std::cerr << "Socket::Bind()::bind err..." << std::endl;
	      return false;
      }
      return true;
   }

   bool Listen()
   {
      if (listen(_sockFd, _backlog) < 0) {
	      std::cerr << "Socket::Listen()::listen err..." << std::endl;
	      return false;
      }
      std::cout << "Socket::Listen()::listening..." << std::endl;
      return true;
   }

   int Accept(std::string* ip, uint16_t* port)
   {
      struct sockaddr_in remote;
      socklen_t len = sizeof(remote);
      int connFd = accept(_sockFd, (struct sockaddr*)&remote, &len);
      if (connFd < 0) {
	      std::cerr << "Socket::Accept()::accept err..." << std::endl;
	      return -1;
      }
      char addrBuffer[32]; addrBuffer[0] = 0;
      if (inet_ntop(AF_INET, &(remote.sin_addr), addrBuffer, sizeof(addrBuffer)) == nullptr) {
         std::cerr << "Socket::Accept()::inet_ntop err..." << std::endl;
         return -1;
      }
      *ip = std::string(addrBuffer);
      *port = ntohs(remote.sin_port);
      return connFd;
   }

   bool Connect(const std::string& ip, uint16_t port)
   {
      struct sockaddr_in remote;
      bzero(&remote, sizeof(remote));
      remote.sin_family = AF_INET;
      remote.sin_port = htons(port);
      remote.sin_addr.s_addr = inet_addr(ip.c_str());
      if (connect(_sockFd, (struct sockaddr*)&remote, sizeof(remote)) < 0) {
	      std::cerr << "Socket::Connect()::connect err..." << std::endl;
	      return false;
      }      
      return true;
   }

   bool Close()
   {
      if (_sockFd < 0) { return false; }
      if (close(_sockFd) < 0) {
	      std::cerr << "Socket::Close()::close err..." << std::endl;
	      return false;
      }
      return true;
   }

   int Fd()
   {
      return _sockFd;
   }

   virtual ~Socket()
   {
      if (_sockFd > 0) {
	      close(_sockFd);
      }
   }

private:
   int _sockFd;
   int _backlog;
};
